%include "arch/const.inc"

extern SysCallCheck
extern SysCallDispatch
extern ExceptionCheck
extern InterruptDoIrq
extern SoftIrqHandle
extern interrupt

extern DisInterrupt
extern EnInterrupt

%if ENABLE_SMP
extern APICTimerUpdate
extern APICPrintError
extern appoint_func
%endif

%define ERROR_CODE nop 
%define NO_ERROR_CODE push 0

global AsmTest
AsmTest:
    int 0x64
    ret

%macro EXCEPTION_ENTRY 2
global ExceptionEntry%1
ExceptionEntry%1:
    %2 ;push error code

    push ds
    push es
    push fs
    push gs
    pushad  ;pushad push all bits32 register
    push %1 ;push vector num

    mov dx,ss
    mov ds,dx
    mov es,dx
    mov fs,dx
    mov gs,dx

    mov eax, [interrupt+8*%1+4]
    push esp
    call eax
    add esp,4

    push esp
    call ExceptionCheck
    add esp,4

    jmp InterruptExit
%endmacro

%macro IRQ_ENTRY 2
global IrqEntry%1
IrqEntry%1:
    %2 
    push ds
    push es
    push fs
    push gs
    pushad 
    push %1 ;irq number

    push edx
    mov dx,ss
	mov ds, dx
	mov es, dx
    mov fs, dx
	mov gs, dx
    pop edx 
    
    push esp
    call InterruptDoIrq
    add esp, 4

    push esp
    call ExceptionCheck
    add esp,4
    jmp InterruptExit
%endmacro

global IrqEntryGeneral
IrqEntryGeneral:
    NO_ERROR_CODE

    push ds
    push es
    push fs
    push gs
    pushad 
    push 0    ;irq number 

    push edx
    xor edx,edx 
    mov dx,ss
    mov ds,dx
    mov es,dx
    mov fs,dx
    mov gs,dx
    pop edx

    push esp
    call InterruptDoIrq
    add esp,4

    push esp
    call ExceptionCheck 
    add esp,4
    jmp InterruptExit

[bits 32]
[section .text]
;define exception entry and irq entry handler use macro 
EXCEPTION_ENTRY 0x00,NO_ERROR_CODE
EXCEPTION_ENTRY 0x01,NO_ERROR_CODE
EXCEPTION_ENTRY 0x02,NO_ERROR_CODE
EXCEPTION_ENTRY 0x03,NO_ERROR_CODE 
EXCEPTION_ENTRY 0x04,NO_ERROR_CODE
EXCEPTION_ENTRY 0x05,NO_ERROR_CODE
EXCEPTION_ENTRY 0x06,NO_ERROR_CODE
EXCEPTION_ENTRY 0x07,NO_ERROR_CODE 
EXCEPTION_ENTRY 0x08,ERROR_CODE
EXCEPTION_ENTRY 0x09,NO_ERROR_CODE
EXCEPTION_ENTRY 0x0a,ERROR_CODE
EXCEPTION_ENTRY 0x0b,ERROR_CODE 
EXCEPTION_ENTRY 0x0c,NO_ERROR_CODE
EXCEPTION_ENTRY 0x0d,ERROR_CODE
EXCEPTION_ENTRY 0x0e,ERROR_CODE
EXCEPTION_ENTRY 0x0f,NO_ERROR_CODE 
EXCEPTION_ENTRY 0x10,NO_ERROR_CODE
EXCEPTION_ENTRY 0x11,ERROR_CODE
EXCEPTION_ENTRY 0x12,NO_ERROR_CODE
EXCEPTION_ENTRY 0x13,NO_ERROR_CODE 
EXCEPTION_ENTRY 0x14,NO_ERROR_CODE
EXCEPTION_ENTRY 0x15,NO_ERROR_CODE
EXCEPTION_ENTRY 0x16,NO_ERROR_CODE
EXCEPTION_ENTRY 0x17,NO_ERROR_CODE 
EXCEPTION_ENTRY 0x18,ERROR_CODE
EXCEPTION_ENTRY 0x19,NO_ERROR_CODE
EXCEPTION_ENTRY 0x1a,ERROR_CODE
EXCEPTION_ENTRY 0x1b,ERROR_CODE 
EXCEPTION_ENTRY 0x1c,NO_ERROR_CODE
EXCEPTION_ENTRY 0x1d,ERROR_CODE
EXCEPTION_ENTRY 0x1e,ERROR_CODE
EXCEPTION_ENTRY 0x1f,NO_ERROR_CODE 
IRQ_ENTRY 0x20,NO_ERROR_CODE	;时钟中断对应的入口
IRQ_ENTRY 0x21,NO_ERROR_CODE	;键盘中断对应的入口
IRQ_ENTRY 0x22,NO_ERROR_CODE	;级联用的
IRQ_ENTRY 0x23,NO_ERROR_CODE	;串口2对应的入口
IRQ_ENTRY 0x24,NO_ERROR_CODE	;串口1对应的入口
IRQ_ENTRY 0x25,NO_ERROR_CODE	;并口2对应的入口
IRQ_ENTRY 0x26,NO_ERROR_CODE	;软盘对应的入口
IRQ_ENTRY 0x27,NO_ERROR_CODE	;并口1对应的入口
IRQ_ENTRY 0x28,NO_ERROR_CODE	;实时时钟对应的入口
IRQ_ENTRY 0x29,NO_ERROR_CODE	;重定向
IRQ_ENTRY 0x2a,NO_ERROR_CODE	;保留
IRQ_ENTRY 0x2b,NO_ERROR_CODE	;保留
IRQ_ENTRY 0x2c,NO_ERROR_CODE	;ps/2鼠标
IRQ_ENTRY 0x2d,NO_ERROR_CODE	;fpu浮点单元异常
IRQ_ENTRY 0x2e,NO_ERROR_CODE	;硬盘
IRQ_ENTRY 0x2f,NO_ERROR_CODE	;保留

[bits 32]
[section .text]  
global SysCallHandler
SysCallHandler:
    ;save status
    push 0     ;push error code
    push ds
    push es
    push fs
    push gs
    pushad      ;pushad instruction push all register 
    push 0x40   ;push vector num
    
    push edx 
    xor edx,edx 
    mov dx,ss 
    mov ds,dx
    mov es,dx
    mov fs,dx
    mov gs,dx
    pop edx 
    
    ;check sycall number 
    push eax
    call SysCallCheck   
    cmp eax,1
    je .BadSysCall
    pop eax 

    ;do syscall dispath function
    push esp
    call SysCallDispatch
    add esp,4
    mov [esp+8*4],eax   ;push retval to frame
.CheckException:
    push esp
    call ExceptionCheck
    add esp,4
    cli 
    jmp InterruptExit
.BadSysCall:
    pop eax
    jmp .CheckException 


%if ENABLE_SMP
global MpExcAppointHandler
MpExcAppointHandler:
    push 0

    push ds
    push es
    push fs
    push gs
    pushad ;pushad instruction push all register
    push 0x71

    push edx 
    mov dx,ss
    mov ds,dx 
    mov es,dx 
    mov fs,dx
    mov gs,dx
    pop edx 
    
    call appoint_func
.CheckException:
    push esp
    call ExceptionCheck
    add esp,4
    jmp InterruptExit

global APICTimerHandler
APICTimerHandler:
    push 0

    push ds
    push es 
    push fs 
    push gs
    pushad 
    push 0x64

    push edx
    mov dx,ss
    mov ds,dx
    mov es,dx
    mov fs,dx
    mov gs,dx
    pop edx 

    call APICTimerUpdate
.CheckException:
    push esp
    call ExceptionCheck
    add esp,4
    jmp InterruptExit

global APICErrHandler
APICErrHandler:
    push 0

    push ds
    push es 
    push fs 
    push gs
    pushad 
    push 0x64

    push edx
    mov dx,ss
    mov ds,dx
    mov es,dx
    mov fs,dx
    mov gs,dx
    pop edx 

    call APICPrintError
.CheckException:
    push esp
    call ExceptionCheck
    add esp,4
   jmp InterruptExit
 %endif
 
global InterruptExit
InterruptExit:
    add esp,4   ;jump vector num
    popad
    pop gs
    pop fs
    pop es
    pop ds
    add esp,4   ;jmp error code
    iretd
